package org.design.hotdevelop.compile;

import lombok.extern.slf4j.Slf4j;
import org.design.hotdevelop.load.HotSwapClassLoader;

import javax.tools.*;
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;

/**
 * @description:
 * @author: freedom
 * @date: 2024/9/25
 **/
@Slf4j
public class CompileSource {

    public static Class<?> compileAndLoadClass(String sourceCode, String className) throws Exception {
        // 创建一个内存中的Java文件对象
        JavaFileObject fileObject = new InMemoryJavaFileObject(className, sourceCode);

        // 获取系统默认的Java编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

        // 设置输出目录
        File outputDir = new File("target/classes");
        if (!outputDir.exists()) {
            outputDir.mkdirs();
        }

        Iterable<? extends JavaFileObject> compilationUnits = Collections.singletonList(fileObject);
        Iterable<String> options = Arrays.asList("-d", outputDir.getAbsolutePath());

        // 编译源代码
        boolean success = compiler.getTask(null, fileManager, null, options, null, compilationUnits).call();

        if (success) {
            log.info("Compilation successful.");
        } else {
            log.info("Compilation failed.");
        }
        // 关闭文件管理器
        fileManager.close();
        // 加载编译后的类
        HotSwapClassLoader classLoader = new HotSwapClassLoader(new URL[]{outputDir.toURI().toURL()});
        return classLoader.loadClass(className);
    }
    static class InMemoryJavaFileObject extends SimpleJavaFileObject {
        private final String code;

        protected InMemoryJavaFileObject(String name, String code) {
            super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
            this.code = code;
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return code;
        }
    }
}
